pub mod vk_config;

/// Vulkan核心层
pub mod vk_context;
/// 结构体封装层
pub mod vk_struct;

pub mod vk_utils;

use std::{ffi::CString, rc::Rc};
use ash::{Entry, Instance, prelude::VkResult, vk};

use self::vk_struct::*;

pub(crate) fn vk_check<T>(vk_result: VkResult<T>, file: &'static str, line: u32) -> Option<T> {
    match vk_result {
        Ok(inner_value) => Some(inner_value),
        Err(err) => {
            println!("[Error] {:180} {}:{}", err, file, line);
            None
        }
    }
}

#[macro_export] 
macro_rules! VK_CHECK {
    ($vk_result: expr) => {
        crate::vulkan::vk_check($vk_result, file!(), line!())
    };
}

#[macro_export] 
macro_rules! VK_CHECK_UNSAFE {
    ($vk_result: expr) => {
        crate::vulkan::vk_check(unsafe{$vk_result}, file!(), line!())
    };
}

/// Vulkan的配置
/// 包括了Feature使用、Extension使用、Log使用
pub struct VkConfig {
    // Instance Info
    pub application_name                : CString,
    pub engine_name                     : CString,
    pub required_layer_names            : Vec<CString>,
    pub required_extension_names        : Vec<CString>,
    pub required_device_extension_names : Vec<CString>,

    // Runtime Save
    pub required_queues                 : Vec<VkRequiredQueue>,
    pub supported_queues                : Vec<VkSupportedQueue>,
    pub device_queue_num                : u32,

    // Debug Utils Config
    pub use_debug_utils                 : bool,
    pub message_severity_flags          : vk::DebugUtilsMessageSeverityFlagsEXT,
    pub message_type_flags              : vk::DebugUtilsMessageTypeFlagsEXT,
    
    pub verbose_log                     : bool,
    pub use_ray_tracing                 : bool
}

/// 可以看出Ash的设计逻辑
/// 原生的Vulkan Function都是定义在.h里面的，所以可以include之后直接使用
/// 但是Ash却将不同功能的Function都封装起来了
/// 例如ash::vk::SurfaceKHR对应的是Cpp里面的VkSurfaceKHR，也就是handler
/// 而操作Surface的函数例如vkGetPhysicalDeviceSurfaceFormatsKHR，在Ash中封装在了ash::extensions::khr::Surface里面，在Load的时候才会加载函数
/// 对应的堆栈为
/// ```
/// ash::extensions::khr::Surface::new(entry, instance)
/// vk::KhrSurfaceFn::load(_f) => 这里面就可以看见Surface层封装的所有函数
/// ```
/// 所以ash::Instance也是函数封装，ash::vk::Instance才是真正和Cpp里面Instance对应的handler
/// 
/// VkContext的初始化逻辑在vk_context.rs
pub struct VkContext {
    pub vk_entry                        : Entry,
    pub vk_instance                     : Instance,
    pub vk_surface                      : VkSurface,
    pub g_window                        : Rc<winit::window::Window>,

    pub vk_debug_utils                  : Option<VkDebugUtils>,

    pub vk_physical_device              : vk::PhysicalDevice,
    pub vk_device                       : ash::Device,
    pub vk_queue_map                    : Vec<Vec<VkQueue>>,
    pub vk_command_pool                 : ash::vk::CommandPool,
    pub vk_descriptor_pool              : ash::vk::DescriptorPool,

    pub current_frame_index             : usize,
    pub current_image_index             : usize,
    pub current_command_buffer          : vk::CommandBuffer,

    pub verbose_log                     : bool
}